/**
  ******************************************************************************
  * @file    mg_driver_gpio.c
  * @author  
  * @version V1.1
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2019 Shanghai Macrogiga Electronics</center></h2>
  *
  ******************************************************************************
  */
#include "mg_driver_gpio.h"
#include "mg_driver_clock.h"



/**
  * @brief   Changes the mapping of the specified pin.                   
  * @param   GPIO_MAP_PINx: specifies the pin for the Alternate function.
  *          This parameter can be GPIO_MAP_PIN_Ax where x can be (0..15).
  * @param   GPIO_MAP_PIN_FUNCx: selects the pin to used as Alternate function.
  * @retval  None
  */
void GPIO_FunctionSelect(u32 GPIO_MAP_PINx, u32 GPIO_MAP_PIN_FUNCx)
{
    u32 t;
    
    t = SysCtrl->FUNCTION_SEL;
    t &= (~(0x00000003 << (2*GPIO_MAP_PINx)));
    
    t |= (GPIO_MAP_PIN_FUNCx << (2*GPIO_MAP_PINx));
    SysCtrl->FUNCTION_SEL = t;
}

/**
  * @brief  Initializes the GPIOx peripheral according to the specified
  *         parameters in the GPIO_InitStruct.
  * @param  GPIOx: where x to select the GPIO peripheral.
  * @param  GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that
  *         contains the configuration information for the specified GPIO peripheral.
  * @retval None
  */
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
    u32 pinpos = 0x00;
    u16 pin = GPIO_InitStruct->GPIO_Pin;

    CLK_SetClockGate(CLK_GATE_GPIO_EN);

    if (GPIO_InitStruct->GPIO_Mode & GPIO_OUTPUT)
    {
        GPIOx->OUT_EN_SET = pin;
    }
    else
    {
        GPIOx->OUT_EN_CLR = pin;
    }
    
    for (pinpos = 0x00; pinpos < 0x10; pinpos++)
    {
        if ((1<<pinpos) & pin)
        {
            SysCtrl->PA_CONF[pinpos] = GPIO_InitStruct->GPIO_Mode&0x07;
        }
    }
}

/**
  * @brief  Reads the specified input port pin.
  * @param  GPIOx: where x can be (A..D) to select the GPIO peripheral.
  * @param  GPIO_Pin:  specifies the port bit to read.
  *   This parameter can be GPIO_Pin_x where x can be (0..15).
  * @retval The input port pin value.
  */
u8 GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, u16 GPIO_Pin)
{
    u8 bitstatus = 0x00;

    if ((GPIOx->DATA_IN & GPIO_Pin) != (u32)Bit_RESET)
    {
        bitstatus = (u8)Bit_SET;
    }
    else
    {
        bitstatus = (u8)Bit_RESET;
    }
    return bitstatus;
}

/**
  * @brief  Reads the specified GPIO input data port.
  * @param  GPIOx: where x to select the GPIO peripheral.
  * @retval GPIO input data port value.
  */
u16 GPIO_ReadInputData(GPIO_TypeDef* GPIOx)
{
  return ((u16)GPIOx->DATA_IN);
}

/**
  * @brief  Reads the specified output data port bit.
  * @param  GPIOx: where x to select the GPIO peripheral.
  * @param  GPIO_Pin:  specifies the port bit to read.
  *         This parameter can be GPIO_Pin_x where x can be (0..15).
  * @retval The output port pin value.
  */
u8 GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, u16 GPIO_Pin)
{
    u8 bitstatus = 0x00;

    if (((GPIOx->DATA_OUT) & GPIO_Pin) != (u32)Bit_RESET)
    {
        bitstatus = (u8)Bit_SET;
    }
    else
    {
        bitstatus = (u8)Bit_RESET;
    }
    return bitstatus;
}

/**
  * @brief  Reads the specified GPIO output data port.
  * @param  GPIOx: where x to select the GPIO peripheral.
  * @retval GPIO output data port value.
  */
u16 GPIO_ReadOutputData(GPIO_TypeDef* GPIOx)
{
    return ((u16)GPIOx->DATA_OUT);
}

/**
  * @brief  Sets the selected data port bits.
  * @param  GPIOx: where x to select the GPIO peripheral.
  * @param  GPIO_Pin: specifies the port bits to be written.
  *         This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
  * @retval None
  */
void GPIO_SetBits(GPIO_TypeDef* GPIOx, u16 GPIO_Pin)
{
    GPIOx->DATA_OUT_SET = GPIO_Pin;
}

/**
  * @brief  Clears the selected data port bits.
  * @param  GPIOx: where x to select the GPIO peripheral.
  * @param  GPIO_Pin: specifies the port bits to be written.
  *         This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
  * @retval None
  */
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, u16 GPIO_Pin)
{
    GPIOx->DATA_OUT_CLEAR = GPIO_Pin;
}

/**
  * @brief  Toggles the specified GPIO pins..
  * @param  GPIOx: where x to select the GPIO peripheral 
  * @param  GPIO_Pin: specifies the port bit to be written.
  *         This parameter can be one of GPIO_Pin_x where x can be (0..15).                  
  * @retval None
  */
void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, u16 GPIO_Pin)
{
    GPIOx->DATA_OUT ^= GPIO_Pin;
}


void GPIO_EXTInt_Init(GPIO_TypeDef* GPIOx, GPIO_EXTInt_TypeDef* type)
{
    switch (type->Trigger_Type)
    {
        case GPIO_Triger_LOW:
            GPIOx->INT_POL_CLR = type->GPIO_Pin;
            GPIOx->INT_TYPE_CLR = type->GPIO_Pin;
            break;
        
        case GPIO_Triger_FALLING_EDGE:
            GPIOx->INT_POL_CLR = type->GPIO_Pin;
            GPIOx->INT_TYPE_SET = type->GPIO_Pin;
            break;
        case GPIO_Triger_HIGH:
            GPIOx->INT_POL_SET = type->GPIO_Pin;
            GPIOx->INT_TYPE_CLR = type->GPIO_Pin;
            break;
        case GPIO_Triger_RISING_EDGE:
            GPIOx->INT_POL_SET = type->GPIO_Pin;
            GPIOx->INT_TYPE_SET = type->GPIO_Pin;
            break;
        default:break;
    }
    
    GPIOx->INT_EN_SET = type->GPIO_Pin;  //enable intterupt
}
